﻿using System.Reflection.Emit;

namespace LxCore
{
    public class TimeStepSet : IterationStepSet
    {
        public TimeStepSet() : base()
        {
            MaxTimeRule = new MaxTimeStopRule(this);
        }
        private MaxTimeStopRule _MaxTimeRule;
        public MaxTimeStopRule MaxTimeRule
        {
            get { return _MaxTimeRule; }
            set { _MaxTimeRule = value; RaisePropertyChanged(nameof(MaxTimeRule)); }
        }

        public double CurrentTime { get; set; }//对于显示格式，Result的时间在离散方程的下一个，对于隐式是一样的，ResultTime即为t时间，对应的时间间隔为delta_t
        public double EquationTime { get; set; }
        public double to { get; set; }
        public double too { get; set; }
        //public double dt { get; set; }
        //public double dto { get; set; }
        //public double dtoo { get; set; }
        public double Factor1st_Phi { get; set; }
        public double Factor2nd_Phi { get; set; }
        public double Factor2nd_PhiO { get; set; }
        public double Factor2nd_PhiOO { get; set; }

        public override void StepStart()
        {
            if (!CurrentStepOngoing)
            {
                CurrentStepOngoing = true;
                CurrentStep++;
                StopBoolCollector = new BoolCollector();
                switch (LxSim.Sim.Physics.TimeDiscreteType)
                {
                    case TimeDiscreteTypes.Explicit_2nd or TimeDiscreteTypes.Explicit_1st:
                        LxSim.Sim.Steps.CurrentTotalStep++;
                        break;
                    case TimeDiscreteTypes.Implicit_2nd or TimeDiscreteTypes.Implicit_1st:
                        LxSim.Sim.Steps.IterationStep.CurrentStep = 0;
                        break;
                }
                //根据current step推进时间
                //var f = LxSim.Sim.Physics.TimeInterval.GetCellVars(null);
                //if (CurrentStep == 1)//第一次计算就进入了Step1，所以回去把Step0补上
                //{
                //    CurrentTime = 0;
                //    dt = f.GetCellVar(0);
                //    dto = 0;
                //}
                //dtoo = dto;
                //dto = dt;
                //dt = f.GetCellVar(CurrentStep);
                //CurrentTime += 0.5 * (dt + dto);//ResultTime对应dt
                var ti = LxSim.Sim.Physics.TimeInterval.GetPara();
                if (CurrentStep == 1)
                {
                    CurrentTime = ti;
                    to = 0;
                    too = 0;
                }
                else
                {
                    too = to;
                    to = CurrentTime;
                    CurrentTime += ti;
                }
            }
            //设置系数
            setFactor();
        }
        private void setFactor()
        {
            FactorCaler f = new FactorCaler();
            f.SetTime(CurrentTime, to, too);
            switch (LxSim.Sim.Physics.TimeDiscreteType)
            {
                case TimeDiscreteTypes.Explicit_2nd or TimeDiscreteTypes.Explicit_1st:
                    Factor1st_Phi = f.GetFactor_Explicit_1stOrder();
                    (Factor2nd_Phi, Factor2nd_PhiO, Factor2nd_PhiOO) = f.GetFactor_Explicit_2ndOrder();
                    EquationTime = to;//显式时EquationTime对应dto
                    break;
                case TimeDiscreteTypes.Implicit_2nd or TimeDiscreteTypes.Implicit_1st:
                    Factor1st_Phi = f.GetFactor_Implicit_1stOrder();
                    (Factor2nd_Phi, Factor2nd_PhiO, Factor2nd_PhiOO) = f.GetFactor_Implicit_2ndOrder();
                    EquationTime = CurrentTime;//隐式时EquationTime对应dt
                    break;
                default:
                    throw new Exception("时间格式未定义");
            }
        }
        public override void StepEnd()
        {
            if (MaxTimeRule != null)
            {
                AddStopBool(MaxTimeRule);
            }
            base.StepEnd();
        }

        public override void FromJsonKV(string key, IJsonReader jsReader)
        {
            switch (key)
            {
                case nameof(CurrentTime): CurrentTime = jsReader.ReadDouble(); break;
                case nameof(MaxTimeRule): jsReader.ReadObject(MaxTimeRule, e => MaxTimeRule = e, t => new MaxTimeStopRule(this)); break;
                case nameof(to): to = jsReader.ReadDouble(); break;
                case nameof(too): too = jsReader.ReadDouble(); break;
                default: base.FromJsonKV(key, jsReader); break;
            }

        }
        public override void ToJsonKV(IJsonWriter jsWriter)
        {
            base.ToJsonKV(jsWriter);
            jsWriter.WriteDouble(nameof(CurrentTime), CurrentTime);
            jsWriter.WriteObject(nameof(MaxTimeRule), MaxTimeRule);
            if (CurrentStep > 0)
            {
                jsWriter.WriteDouble(nameof(to), to);
                jsWriter.WriteDouble(nameof(too), too);
            }
        }
        public class MaxTimeStopRule : StopRuleBase
        {
            public MaxTimeStopRule(TimeStepSet transStep)
            {
                this.TimeStep = transStep;
            }
            private TimeStepSet TimeStep;

            private double _MaxTime = 1;
            public double MaxTime
            {
                get { return _MaxTime; }
                set { _MaxTime = value; RaisePropertyChanged(nameof(MaxTime)); }
            }

            public override bool IsStop()
            {
                return TimeStep.CurrentTime >= MaxTime;
            }
            public override void FromJsonKV(string key, IJsonReader jsReader)
            {
                switch (key)
                {
                    case nameof(MaxTime): MaxTime = jsReader.ReadDouble(); break;
                    default: base.FromJsonKV(key, jsReader); break;
                }
            }
            public override void ToJsonKV(IJsonWriter jsWriter)
            {
                base.ToJsonKV(jsWriter);
                jsWriter.WriteDouble(nameof(MaxTime), MaxTime);
            }
        }
        public struct FactorCaler
        {
            public double dt;
            public double dto;
            public double dtoo;
            public void SetTime(double t, double to, double too)
            {
                double t_to = t - to;
                if (to == too)
                {
                    dt = t_to;
                    dto = dt;
                    dtoo = dt;
                }
                else
                {
                    double to_too = to - too;
                    if (to_too < t_to)
                    {
                        dto = dtoo = to_too;
                        dt = 2 * t_to - to_too;
                    }
                    else
                    {
                        dto = dt = t_to;
                        dtoo = 2 * to_too - t_to;
                    }
                }
            }
            public double GetFactor_Explicit_1stOrder()
            {
                return 1.0 / dto;
            }
            public (double beforePhi, double beforePhiOld, double beforePhiOld2) GetFactor_Explicit_2ndOrder()
            {
                double beforePhiOld2 = (dt + 2 * dto) * dto / ((dt + 2 * dto + dtoo) * (dto + dtoo));
                double beforePhiOld = (dt + 2 * dto) * dtoo / ((dt + dto) * (dto + dtoo));
                double beforePhi = 1 - beforePhiOld - beforePhiOld2;
                beforePhi = dto / (dt + dto) - beforePhi;
                beforePhiOld = dt / (dt + dto) - beforePhiOld;
                beforePhi /= dto;
                beforePhiOld /= dto;
                beforePhiOld2 /= -dto;
                return (beforePhi, beforePhiOld, beforePhiOld2);
            }
            public double GetFactor_Implicit_1stOrder()
            {
                return 1.0 / dt;
            }
            public (double beforePhi, double beforePhiOld, double beforePhiOld2) GetFactor_Implicit_2ndOrder()//放在左侧时的factor
            {
                double beforePhi = 1.0 / dt + 1.0 / (dt + dto);
                double beforePhiOld2 = dto / (dt * (dto + dtoo));
                return (beforePhi, -(beforePhi + beforePhiOld2), beforePhiOld2);
            }
        }
    }
}
//double GetFactor_Explicit_1stOrder(double dt, double dto)
//{
//    return 1.0 / dto;
//}
//(double beforePhi, double beforePhiOld, double beforePhiOld2) GetFactor_Explicit_2ndOrder(double dt, double dto, double dtoo)
//{
//    double beforePhiOld2 = (dt + 2 * dto) * dto / ((dt + 2 * dto + dtoo) * (dto + dtoo));
//    double beforePhiOld = (dt + 2 * dto) * dtoo / ((dt + dto) * (dto + dtoo));
//    double beforePhi = 1 - beforePhiOld - beforePhiOld2;
//    beforePhi = dto / (dt + dto) - beforePhi;
//    beforePhiOld = dt / (dt + dto) - beforePhiOld;
//    beforePhi /= dto;
//    beforePhiOld /= dto;
//    beforePhiOld2 /= -dto;
//    return (beforePhi, beforePhiOld, beforePhiOld2);
//}
//double GetFactor_Implicit_1stOrder(double dt, double dto)
//{
//    return 1.0 / dt;
//}
//(double beforePhi, double beforePhiOld, double beforePhiOld2) GetFactor_Implicit_2ndOrder(double dt, double dto, double dtoo)//放在左侧时的factor
//{
//    double beforePhi = 1.0 / dt + 1.0 / (dt + dto);
//    double beforePhiOld2 = dto / (dt * (dto + dtoo));
//    return (beforePhi, -(beforePhi + beforePhiOld2), beforePhiOld2);
//}